package org.jrfe.gfx;

import java.nio.FloatBuffer;

import org.jrfe.JRFE;
import org.jrfe.util.BufferUtil;
import org.lwjgl.BufferUtils;

/**
 * VertexBatch is Set of vertexes,colors and texture coordinate 
 * that make up render able geometry 
 * 
 * Elements in vertexBtach are points in geometry shape (Rectangle has 4 elements, Triangle has 3 elements) 
 * 
 * @author Kalvis Freimanis
 *
 */
public class VertexBatch {
	/**
	 * VertexBatch type There are 2 types SIMPLE this one 
	 * and INDEXED see {@link IdxVertexBatch}
	 */
	protected BatchType batchType;

	/**
	 * Vertex Buffer
	 * buffer size is elements * 2
	 * x and y coordinates are stored in buffer as follow {x,y,x,y,x,y...}
	 */
	protected FloatBuffer vertexs;
	
	/**
	 * Color Buffer
	 * buffer size is elements * 4
	 * r,g,b and a values are stored in buffer as follow {r,g,b,a,r,g,b,a,r,g,b,a...}
	 */
	protected FloatBuffer colors;
	
	/**
	 * Texture coordinates Buffer
	 * buffer size is elements * 2
	 * s and t coordinates are stored in buffer as follow {s,t,s,t,s,t...}
	 */
	protected FloatBuffer texCords;

	/**
	 * Used elements count in VertexBatch 
	 */
	protected int elements;
	/**
	 * Maximal allowed elements in this VertexBtach 0 to maxElements-1 
	 */
	protected int maxElements;
	
	/**
	 * Type of geometry/primitive type to be rendered form this VertexBatch {@link JRFE.PrimitiveTypes} 
	 */
	protected int ptype;
	
	/**
	 * Texture Id to be used when rendering this VertexBatch
	 * Value 0 is no texture
	 */
	protected int texture;
	
	/**
	 * Create new VertexBatch with specified number of elements
	 * Elements are points in geometry (Rectangle has 4 elements, Triangle has 3 elements) 
	 * @param elements Number of elements
	 */
	public VertexBatch(int elements) {
	
		this.elements = elements;
		this.maxElements = elements;
		batchType = BatchType.SIMPLE;
		vertexs = BufferUtils.createFloatBuffer(elements * 2);
		colors = BufferUtils.createFloatBuffer(elements * 4);
		texCords = BufferUtils.createFloatBuffer(elements * 2);
	}

	/**
	 * Resize size of this VertexBatch
	 * if new size is same old one nothing is done
	 * if new size is bigger that old one VertexBatch is resized and data is intact 
	 * if new size is smaller that old one VertexBatch is resized and data is deleted
	 * @param newElementCount
	 */
	public void resize(int newElementCount){
		if(maxElements == newElementCount){
			return;
		}
		
		if(maxElements < newElementCount){
			
			vertexs = BufferUtil.copyBuffer(newElementCount * 2, vertexs);
			colors = BufferUtil.copyBuffer(newElementCount * 4, colors);
			texCords = BufferUtil.copyBuffer(newElementCount * 2, texCords);
	
		}else{
			
			vertexs = BufferUtils.createFloatBuffer(newElementCount * 2);
			colors = BufferUtils.createFloatBuffer(newElementCount * 4);
			texCords = BufferUtils.createFloatBuffer(newElementCount * 2);
			
			
		}
		
		maxElements = newElementCount;
		elements = maxElements;
		
	}
	
	/**
	 * Update vertex values for VertexBatch
	 * @param idx index {x coordinate of element = element*2} 
	 * 					{y coordinate of element = element*2+1}
	 * @param value value to set at index
	 */
	public void updateVertex(int idx, float value) {
		vertexs.put(idx, value);
	}

	/**
	 * Update Color values for VertexBatch
	 * @param idx index {Red of element = element*2} 
	 * 					{Green of element = element*2+1}
	 * 					{Blue of element = element*2+2}
	 * 					{Alpha of element = element*2+3}
	 * @param value value to set at index
	 */
	public void updateColor(int idx, float value) {
		colors.put(idx, value);
	}
	
	
	/**
	 * Update Texture coordinate values for VertexBatch
	 * @param idx index {s coordinate of element = element*2} 
	 * 					{t coordinate of element = element*2+1}
	 * @param value value to set at index
	 */
	public void updateTexCord(int idx, float value) {
		texCords.put(idx, value);
	}
	
	/**
	 * Update Vertex values of element
	 * @param element index
	 * @param x new x coordinate
	 * @param y new y coordinate
	 */
	public void updateVertex(int element,float x,float y){
		int idx = element * 2;
		vertexs.put(idx,x);
		vertexs.put(idx+1,y);
	}
	
	/**
	 * Update Texture coordinate values of element
	 * @param element index of elements
	 * @param s new s coordinate
	 * @param t new t coordinate
	 */
	public void updateTexCord(int element,float s,float t){
		int idx = element * 2;
		texCords.put(idx, s);
		texCords.put(idx+1, t);		
	}
	
	/**
	 * Update Color for element
	 * @param element index of elements
	 * @param color new Color for this element
	 */
	public void updateColor(int element,ColorRGBA color){
		int idx = element * 4;
		colors.put(idx,color.r);
		colors.put(idx+1,color.g);
		colors.put(idx+2,color.b);
		colors.put(idx+3,color.a);
	}
	
	/**
	 * Update elements
	 * @param element index of element update
	 * @param vert {@link Vertex} object for this element 
	 * (Only Values are copied from vertex object 
	 * afterward object is not used any more in VertexBatch )
	 */
	public void update(int element,Vertex vert){
		int idx = element * 2;
		vertexs.put(idx,vert.x);
		vertexs.put(idx+1,vert.y);

		idx = element * 4;
		colors.put(idx,vert.r);
		colors.put(idx+1,vert.g);
		colors.put(idx+2,vert.b);
		colors.put(idx+3,vert.a);
	
		idx = element * 2;
		texCords.put(idx,vert.s);
		texCords.put(idx+1,vert.t);
	}

	/**
	 * Get element form Vertexbatch
	 * @param element index of element to get
	 * @param dataVertex pass vertex where to put data in to 
	 * if null then new {@link Vertex} is created
	 * 
	 * @return {@link Vertex} with data
	 */
	public Vertex getElement(int element,Vertex dataVertex){
		
		Vertex v = dataVertex;
		if(v == null){
			v = new Vertex();
		}
		
		
		int idx = element * 2;
		v.x = vertexs.get(idx);
		v.y = vertexs.get(idx+1);
	
		idx = element * 4;
		v.r = colors.get(idx);
		v.g = colors.get(idx+1);
		v.b = colors.get(idx+2);
		v.a = colors.get(idx+3);
	
		idx = element * 2;
		v.s = texCords.get(idx);
		v.t = texCords.get(idx+1);

		return v;
	}
	
	/**
	 * Get Texture Id
	 * @return texture id or 0 if no texture
	 */
	public int getTexture() {
		return texture;
	}
	
	/**
	 * Set Texture ID
	 * @param texture Texture ID 
	 */
	public void setTexture(int texture) {
		this.texture = texture;
	}

	/**
	 * Get Number of elements to be used
	 * @return used element count
	 */
	public int getElements() {
		return elements;
	}

	/**
	 * Set used element count (be careful not to set this bigger that getMaxElements())
	 * @param elements
	 */
	public void setElements(int elements) {
		this.elements = elements;
	}

	/**
	 * Get geometry/primitive type 
	 * @return geometry/primitive type {@link JRFE.PrimitiveTypes}
	 */
	public int getPtype() {
		return ptype;
	}

	/**
	 * Set geometry/primitive type 
	 * @param ptype geometry/primitive type
	 */
	public void setPtype(int ptype) {
		this.ptype = ptype;
	}

	/**
	 * Get Vertex {@link BatchType}
	 * @return BatchType
	 */
	public BatchType getBatchType() {
		return batchType;
	}

	/**
	 * Get vertex buffer
	 * If used for changing data in buffer call Buffer.flip() after changing
	 * @return Vertex Buffer
	 */
	public FloatBuffer getVertexs() {
		return vertexs;
	}

	/**
	 * Get Color buffer
	 * If used for changing data in buffer call Buffer.flip() after changing
	 * @return Color Buffer
	 */
	public FloatBuffer getColors() {
		return colors;
	}

	/**
	 * Get Texture Coordinates buffer
	 * If used for changing data in buffer call Buffer.flip() after changing
	 * @return Texture Coordinates Buffer
	 */
	public FloatBuffer getTexCords() {
		return texCords;
	}

	
	/**
	 * Get Maximal allowed elements in this vertex batch 0 to maxElements-1
	 * @return Maximal allowed elements in this vertex batch
	 */
	public int getMaxElements() {
		return maxElements;
	}
	
	

}
